﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls;
using Passwords.Biz;
using Passwords.Images;
using Silvermoon.Images;
using Passwords.Utils;
using Silvermoon.Windows.Styles;
using Passwords.Controls;

namespace Passwords.Pages
{
    /// <summary>
    /// Page that displays a collection of labels.
    /// a) if created with parameter password=null, the collection is the set of all labels, and selecting one label causes to open the label editor.
    /// b) if created with parameter password!=null, the collection is the set of all labels excluding the labels already in the password, and selecting on label
    ///     raises the ItemChosenEvent.
    /// </summary>
    public class LabelPickerPage : Page
    {
        const string az = "#ABCDEFGIJKLMNOPQRSTUVWXYZ";
        private ListView azListView, indexListView;
        private TabControl tab;
        private ListViewController<IndexItem, PasswordLabel> azController;
        private ListViewController<IndexItem, PasswordLabel> indexController;
        private ContextMenu itemMenu;
        private TabPage azPage, indexPage;

        public LabelPickerPage()
            : base()
        {
            Title = "EDIT LABELS";
            InitializePage();
        }

        public LabelPickerPage(Password password)
            : base()
        {
            Title = "CHOOSE LABEL";
            this.Password = password;
            InitializePage();

        }

        protected override void Dispose(bool dispose)
        {
            base.Dispose(dispose);
        }

        public PasswordLabel SelectedLabel { get; set; }
        public Password Password { get; private set; }

        private void InitializePage()
        {
            Styles = StylePool.Metro;
            Style = StylePool.EditWindow;
            tab = new TabControl { Margin = new Margin(0), TabSpace = 10 };

            Style tabStyle = new LabelStyle { Font = FontCache.BigRegularFont, FontScale = 1.5f, Margin = Margin.Centered };
            azListView = new ListView { Margin = Margin.Zero };
            indexListView = new ListView { Margin = Margin.Zero };

            azPage = new TabPage(new Label("alphabetic ") { Margin = Margin.Centered, Style = tabStyle }, azListView);
            indexPage = new TabPage(new Label("indexed ") { Margin = Margin.Centered, Style = tabStyle }, indexListView);


            tab.SetPages(azPage, indexPage);

            Controls.Add(tab);
            azController = new ListViewController<IndexItem, PasswordLabel>(azListView);
            azController.InitializeItem += new EventHandler<ItemControlGeneratorEventArgs<IndexItem>>(controller_InitializeItem);
            azController.UpdateItem += new EventHandler<ItemControlGeneratorEventArgs<IndexItem>>(controller_UpdateItem);
            azController.ItemHeight = 80;

            indexController = new ListViewController<IndexItem, PasswordLabel>(indexListView);
            indexController.InitializeItem += controller_InitializeItem;
            indexController.UpdateItem += controller_UpdateItem;
            indexController.ItemHeight = 80;
            tab.SelectedPage = azPage;

            SetControllerIndex();

            Toolbar toolbar = new Toolbar();
            Toolbar = toolbar;
            toolbar.AddButton(SysImages.Back, Page.BackCommand);
            toolbar.AddButton(SysImages.Add).Tap += new EventHandler<TapEventArgs>(OnAddLabel);

            itemMenu = new ContextMenu();
            itemMenu.AddItem("Move").Tap += new EventHandler<TapEventArgs>(OnMoveItem);
            SetDataSource();
        }

        void OnMoveItem(object sender, EventArgs e)
        {
            Item item = itemMenu.AnchorControl as Item;
            if (item != null)
            {
                PasswordLabel label = item.DataValue as PasswordLabel;
                LabelIndexPicker page = new LabelIndexPicker { Label = label };
                this.NavigateTo(page);
            }
        }

        void OnAddLabel(object sender, TapEventArgs e)
        {
            PasswordLabel label = new PasswordLabel() { DisplayIndex = Context.Current.Labels.Count };
            NewLabelDetailPage page = new NewLabelDetailPage { Label = label };
            this.NavigateTo(page);
        }

        private void SetDataSource()
        {
            IEnumerable<PasswordLabel> labels = Context.Current.Labels;
            if (Password != null)
            {
                var exclude = Password.EditItems.Select(i => i.Label);
                labels = labels.Except(exclude);
            }
            var ds = from l in labels orderby l.Name, l.DisplayIndex select l;
            azController.DataSource = ds;

            var ds2 = from l in labels orderby l.DisplayIndex select l;
            indexController.DataSource = ds2;
        }

        private void SetControllerIndex()
        {
            foreach (char c in az)
            {
                azController.AddIndex(c.ToString());
            }
            azController.GetDescriptorFromValue += new EventHandler<GroupDescriptorEventArgs<PasswordLabel>>(controller_GetDescriptorFromValue);
        }

        void controller_GetDescriptorFromValue(object sender, GroupDescriptorEventArgs<PasswordLabel> e)
        {
            string s = e.Value.Name;
            char c = char.ToUpper(s.Length > 0 ? s[0] : '#');
            int index = Math.Max(0, az.IndexOf(c));
            e.Descriptor = e.GroupDescriptors[index];
        }

        void controller_UpdateItem(object sender, ItemControlGeneratorEventArgs<IndexItem> e)
        {
            var item = e.Item;
            PasswordLabel label = e.Value as PasswordLabel;

            item.Index = label.DisplayIndex;
            item.Name = label.Name;
        }

        void controller_InitializeItem(object sender, ItemControlGeneratorEventArgs<IndexItem> e)
        {
            var item = e.Item;
            item.ContextMenu = itemMenu;
            item.Tap += new EventHandler<TapEventArgs>(item_Tap);
        }

        void item_Tap(object sender, EventArgs e)
        {
            Item item = sender as Item;
            PasswordLabel label = item.DataValue as PasswordLabel;
            SelectedLabel = label;
            if (ItemChosen != null)
            {
                ItemChosen(this, EventArgs.Empty);
            }
            else
            {
                EditLabelDetailPage page = new EditLabelDetailPage { Label = label };
                this.NavigateTo(page);
            }
        }

        private class Bag
        {
            public int pageIndex;
            public int azOffset;
            public int indexOffset;
        }

        public override object OnSaveViewState()
        {
            Bag bag = new Bag();
            bag.pageIndex = tab.SelectedPage == azPage ? 0 : 1;
            bag.azOffset = azListView.YOffset;
            bag.indexOffset = indexListView.YOffset;
            return bag;
        }

        public override void OnLoadViewState(object viewState)
        {
            Bag bag = viewState as Bag;
            if (bag != null)
            {
                tab.SelectedPage = bag.pageIndex == 0 ? azPage : indexPage;
                azListView.YOffset = bag.azOffset;
                indexListView.YOffset = bag.indexOffset;
            }
        }

        public event EventHandler ItemChosen;
    }
}
